package org.ooda.distributedsys.functionmodule.function;

import com.mathworks.toolbox.javabuilder.MWClassID;
import com.mathworks.toolbox.javabuilder.MWNumericArray;
import org.ooda.distributedsys.functionmodule.common.ResponseHandler;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;
import ronghe.Ronghe;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.Objects;
import java.util.Queue;

/**
 * @program: distributedSys
 * @description: 综合性能指标函数
 * @author: Aprilies
 * @create: 2023-03-28 22:38
 **/

@RestController
@RequestMapping("/combinationproperty/")
public class CombinationPropertyController {

    private final Queue<Runnable> requestQueue = new LinkedList<>();

    private boolean isProcessingRequest = false;

    /**
     * if validate, return true
     * @param count
     * @return
     */
    private boolean checkCountIsValidate(Double count){
        return count >= 6 && count <= 40;
    }

    private boolean checkSumIsOne(double[] x){
        double sum = 0;
        for (double v : x) {
            sum += v;
            if(v < 0 || v > 1)
                return false;
        }
        return sum == 1;
    }

    private boolean checkParamIsBetween0and1(double[] params){
        for (double param : params) {
            if(param < 0 || param > 1)
                return false;
        }
        return true;
    }

    /**
     * check multi function params is validate, the rule is:
     * 1,start < end
     * 2,start and end is validate by checkCountIsValidate
     * 3,step >= 1
     * 4,batch num is less than 10
     * @param start
     * @param end
     * @return
     */
    private boolean checkParamsIsValidate(Integer start, Integer end, Integer step){
        if(start > end)
            return false;
        if(!(checkCountIsValidate((double) start) && checkCountIsValidate((double)end)))
            return false;
        if(step < 1)
            return false;
        if((end - start/ step) > 10)
            return false;
        return true;
    }

    @PostMapping("ronghe/12")
    public ResponseEntity<?> ronghe12(@RequestParam(value = "count", defaultValue = "20") Double count){
        if (!checkCountIsValidate(count)){
            return ResponseHandler.generateResponse("count is not validate", HttpStatus.BAD_REQUEST, null);
        }
        Object[] objects = new Object[0];
        try {
            Ronghe ronghe = new Ronghe();
            MWNumericArray MW_count = new MWNumericArray(count, MWClassID.DOUBLE);
            objects = ronghe.ronghe1_2(4, MW_count);
            MW_count.dispose();
            ronghe.dispose();
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseHandler.generateResponse("function runtime error", HttpStatus.INTERNAL_SERVER_ERROR, null);
        }
        // 处理得到的四个返回值，第一个key=E_x，第二个key=E_origin，第三个key=E_judge
        // 第四个key=alloc，第五个key=edge_alloc，最后一个key=matrix
        HashMap<String, Object> ret = new HashMap<>();
        ret.put("E_x", ((MWNumericArray) objects[0]).getDouble());
        ret.put("E_origin", ((MWNumericArray) objects[1]).getDouble());
        ret.put("E_judge", ((MWNumericArray) objects[2]).getDouble());
        ret.put("alloc", ((MWNumericArray) objects[3]).toIntArray());

        return ResponseHandler.generateResponse("success", HttpStatus.OK, ret);
    }

    @PostMapping("ronghe/35")
    public ResponseEntity<?> ronghe35(@RequestParam(value = "count", defaultValue = "20") Double count,
                                      @RequestParam(value = "Boe", defaultValue = "0.2") Double Boe,
                                      @RequestParam(value = "Bor", defaultValue = "0.3") Double Bor,
                                      @RequestParam(value = "Bop", defaultValue = "0.5") Double Bop,
                                      @RequestParam(value = "Pse", defaultValue = "0.8") Double Pse,
                                      @RequestParam(value = "Psr", defaultValue = "0.72") Double Psr,
                                      @RequestParam(value = "Psp", defaultValue = "0.33") Double Psp,
                                      @RequestParam(value = "Pdt", defaultValue = "0.77") Double Pdt,
                                      @RequestParam(value = "Pdd", defaultValue = "0.62") Double Pdd,
                                      @RequestParam(value = "Pdm", defaultValue = "0.5") Double Pdm,
                                      @RequestParam(value = "Pdi", defaultValue = "0.95") Double Pdi,
                                      @RequestParam(value = "BAfe", defaultValue = "0.95") Double BAfe,
                                      @RequestParam(value = "BAee", defaultValue = "0.05") Double BAee,
                                      @RequestParam(value = "PAf", defaultValue = "0.54") Double PAf,
                                      @RequestParam(value = "PAe", defaultValue = "0.82") Double PAe,
                                      @RequestParam(value = "x_1", defaultValue = "0.8") Double x_1,
                                      @RequestParam(value = "x_2", defaultValue = "0.2") Double x_2){
        if (!(checkCountIsValidate(count) || checkSumIsOne(new double[]{Boe,Bor,Bop}) || checkSumIsOne(new double[]{BAfe,BAee}) || checkSumIsOne(new double[]{x_1,x_2}) || checkParamIsBetween0and1(new double[]{Pse,Psr,Psp,Pdt,Pdd,Pdm,Pdi,PAf,PAe}))){
            return ResponseHandler.generateResponse("count is not validate", HttpStatus.BAD_REQUEST, null);
        }
        Object[] objects = new Object[0];
        try {
            Ronghe ronghe = new Ronghe();
            MWNumericArray MW_count = new MWNumericArray(count, MWClassID.DOUBLE);
            MWNumericArray MW_Boe = new MWNumericArray(Boe, MWClassID.DOUBLE);
            MWNumericArray MW_Bor = new MWNumericArray(Bor, MWClassID.DOUBLE);
            MWNumericArray MW_Bop = new MWNumericArray(Bop, MWClassID.DOUBLE);
            MWNumericArray MW_Pse = new MWNumericArray(Pse, MWClassID.DOUBLE);
            MWNumericArray MW_Psr = new MWNumericArray(Psr, MWClassID.DOUBLE);
            MWNumericArray MW_Psp = new MWNumericArray(Psp, MWClassID.DOUBLE);
            MWNumericArray MW_Pdt = new MWNumericArray(Pdt, MWClassID.DOUBLE);
            MWNumericArray MW_Pdd = new MWNumericArray(Pdd, MWClassID.DOUBLE);
            MWNumericArray MW_Pdm = new MWNumericArray(Pdm, MWClassID.DOUBLE);
            MWNumericArray MW_Pdi = new MWNumericArray(Pdi, MWClassID.DOUBLE);
            MWNumericArray MW_BAfe = new MWNumericArray(BAfe, MWClassID.DOUBLE);
            MWNumericArray MW_BAee = new MWNumericArray(BAee, MWClassID.DOUBLE);
            MWNumericArray MW_PAf = new MWNumericArray(PAf, MWClassID.DOUBLE);
            MWNumericArray MW_PAe = new MWNumericArray(PAe, MWClassID.DOUBLE);
            MWNumericArray MW_x_1 = new MWNumericArray(x_1, MWClassID.DOUBLE);
            MWNumericArray MW_x_2 = new MWNumericArray(x_2, MWClassID.DOUBLE);
            objects = ronghe.ronghe3_5(6, MW_count,MW_Boe,MW_Bor,MW_Bop,MW_Pse,MW_Psr,MW_Psp,MW_Pdt,MW_Pdd,MW_Pdm,MW_Pdi,MW_BAfe,MW_BAee,MW_PAf,MW_PAe,MW_x_1,MW_x_2);
            MW_count.dispose();
            MW_Boe.dispose();
            MW_Bor.dispose();
            MW_Bop.dispose();
            MW_Pse.dispose();
            MW_Psr.dispose();
            MW_Psp.dispose();
            MW_Pdt.dispose();
            MW_Pdd.dispose();
            MW_Pdm.dispose();
            MW_Pdi.dispose();
            MW_BAfe.dispose();
            MW_BAee.dispose();
            MW_PAf.dispose();
            MW_PAe.dispose();
            MW_x_1.dispose();
            MW_x_2.dispose();
            ronghe.dispose();
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseHandler.generateResponse("function runtime error", HttpStatus.INTERNAL_SERVER_ERROR, null);
        }
        // 处理得到的四个返回值，第一个key=E_x，第二个key=E_origin，第三个key=E_judge
        // 第四个key=alloc，第五个key=edge_alloc，最后一个key=matrix
        HashMap<String, Object> ret = new HashMap<>();
        ret.put("E_x", ((MWNumericArray) objects[0]).getDouble());
        ret.put("E_origin", ((MWNumericArray) objects[1]).getDouble());
        ret.put("E_judge", ((MWNumericArray) objects[2]).getDouble());
        ret.put("alloc", ((MWNumericArray) objects[3]).toIntArray());
        ret.put("alloc_new", ((MWNumericArray) objects[4]).toIntArray());
        ret.put("matrix", ((MWNumericArray) objects[5]).toIntArray());

        return ResponseHandler.generateResponse("success", HttpStatus.OK, ret);
    }

    @PostMapping("ronghe/34")
    public ResponseEntity<?> ronghe34(@RequestParam(value = "count", defaultValue = "20") Double count){
        if (!checkCountIsValidate(count)){
            return ResponseHandler.generateResponse("count is not validate", HttpStatus.BAD_REQUEST, null);
        }
        Object[] objects = new Object[0];
        try {
            Ronghe ronghe = new Ronghe();
            MWNumericArray MW_count = new MWNumericArray(count, MWClassID.DOUBLE);
            objects = ronghe.ronghe3_4(4, MW_count);
            MW_count.dispose();
            ronghe.dispose();
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseHandler.generateResponse("function runtime error", HttpStatus.INTERNAL_SERVER_ERROR, null);
        }
        // 处理得到的四个返回值，第一个key=E_x，第二个key=E_origin，第三个key=E_judge
        // 第四个key=alloc，第五个key=edge_alloc，最后一个key=matrix
        HashMap<String, Object> ret = new HashMap<>();
        ret.put("E_x", ((MWNumericArray) objects[0]).getDouble());
        ret.put("E_origin", ((MWNumericArray) objects[1]).getDouble());
        ret.put("E_judge", ((MWNumericArray) objects[2]).getDouble());
        ret.put("alloc", ((MWNumericArray) objects[3]).toIntArray());

        return ResponseHandler.generateResponse("success", HttpStatus.OK, ret);
    }

    /**
     * 综合效能指标：获取范围内的综合效能结果。返回分配方案与无人机邻接矩阵为start调用ronghe35获得的结果。
     * @param start
     * @param end
     * @param step
     * @return
     */

    @PostMapping("ronghe/multi")
    public DeferredResult<ResponseEntity<?>> getMultiRonghe(@RequestParam(value = "start", defaultValue = "15") Integer start,
                                                             @RequestParam(value = "end", defaultValue = "15") Integer end,
                                                             @RequestParam(value = "step", required = false,defaultValue = "1") Integer step,
                                                             @RequestParam(value = "Boe", defaultValue = "0.2") Double Boe,
                                                             @RequestParam(value = "Bor", defaultValue = "0.3") Double Bor,
                                                             @RequestParam(value = "Bop", defaultValue = "0.5") Double Bop,
                                                             @RequestParam(value = "Pse", defaultValue = "0.8") Double Pse,
                                                             @RequestParam(value = "Psr", defaultValue = "0.72") Double Psr,
                                                             @RequestParam(value = "Psp", defaultValue = "0.33") Double Psp,
                                                             @RequestParam(value = "Pdt", defaultValue = "0.77") Double Pdt,
                                                             @RequestParam(value = "Pdd", defaultValue = "0.62") Double Pdd,
                                                             @RequestParam(value = "Pdm", defaultValue = "0.5") Double Pdm,
                                                             @RequestParam(value = "Pdi", defaultValue = "0.95") Double Pdi,
                                                             @RequestParam(value = "BAfe", defaultValue = "0.95") Double BAfe,
                                                             @RequestParam(value = "BAee", defaultValue = "0.05") Double BAee,
                                                             @RequestParam(value = "PAf", defaultValue = "0.54") Double PAf,
                                                             @RequestParam(value = "PAe", defaultValue = "0.82") Double PAe,
                                                             @RequestParam(value = "x_1", defaultValue = "0.8") Double x_1,
                                                             @RequestParam(value = "x_2", defaultValue = "0.2") Double x_2) {
        if (!checkParamsIsValidate(start, end, step)) {
            DeferredResult<ResponseEntity<?>> deferredResult = new DeferredResult<>();
            ResponseEntity<?> response = ResponseHandler.generateResponse("the params is not validate", HttpStatus.BAD_REQUEST, null);
            deferredResult.setResult(response);
            return deferredResult;
        }

        DeferredResult<ResponseEntity<?>> deferredResult = new DeferredResult<>();

        Runnable requestTask = () -> {
            String[] retKeys = {"one","two","three","four","five","six","seven","eight","nine","ten"};
            HashMap<String, Object> ret = new HashMap<>();
            int j = 0;
            for (int i = start; i <= end; i += step){
                HashMap<String, Object> chart = new HashMap<>();
                HashMap<?,?> data12 = (HashMap<?, ?>)((HashMap<?, ?>) Objects.requireNonNull(ronghe12((double) i).getBody())).get("data");
                HashMap<?,?> data34 = (HashMap<?, ?>)((HashMap<?, ?>) Objects.requireNonNull(ronghe34((double) i).getBody())).get("data");
                HashMap<?,?> data35 = (HashMap<?, ?>)((HashMap<?, ?>) Objects.requireNonNull(ronghe35((double) i, Boe, Bor, Bop, Pse, Psr, Psp, Pdt, Pdd, Pdm, Pdi, BAfe, BAee, PAf, PAe, x_1, x_2).getBody())).get("data");
                if (i == start){
                    HashMap<String, Object> figure = new HashMap<>();
                    figure.put("alloc_new", data35.get("alloc_new"));
                    figure.put("matrix", data35.get("matrix"));
                    ret.put("figure", figure);
                    data35.remove("alloc_new");
                    data35.remove("matrix");
                }
                chart.put("firstComparison", data12);
                chart.put("secondComparison", data34);
                chart.put("thirdComparison", data35);
                ret.put(retKeys[j], chart);
                j++;
            }
            ResponseEntity<?> response = ResponseHandler.generateResponse("success", HttpStatus.OK, ret);
            deferredResult.setResult(response);
            synchronized (this) {
                isProcessingRequest = false;
                if (!requestQueue.isEmpty()) {
                    // If there are pending requests, process the next one
                    Runnable nextRequest = requestQueue.poll();
                    nextRequest.run();
                }
            }
        };

        if (isProcessingRequest) {
            // If another request is already being processed, enqueue the current request
            requestQueue.offer(requestTask);
        } else {
            // Process the current request
            isProcessingRequest = true;
            requestTask.run();
        }

        return deferredResult;
    }
}
